﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Server.Core.Serialization.BooMessaging.Contracts
{
    public class BooObjectContract : BooContract
    {
        private readonly ContractMemberInfo[] _members;

        public BooObjectContract(Type type)
            : base(type)
        {
            // TODO init members
        }

        public override bool IsPackage
        {
            get { return true; }
        }

        protected override void DoWrite(BooMessageWriter writer, object obj)
        {
            foreach (var member in _members)
            {
                var isPackage = member.Contract.IsPackage;

                if (isPackage)
                {
                    writer.StartPackage();
                }

                var value = member.ValueGetter(obj);
                member.Contract.Write(writer, value);

                if (isPackage)
                {
                    writer.EndPackage();
                }
            }
        }

        private class ContractMemberInfo
        {
            /// <summary>
            /// Gets or sets the <see cref="BooContract"/> used to serialize this property/field.
            /// </summary>
            public BooContract Contract { get; set; }

            /// <summary>
            /// Gets the name of the property/field.
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// Gets the property type or field type of the member.
            /// </summary>
            public Type Type { get; set; }

            /// <summary>
            /// Indicates if the class member is a property.
            /// <c>true</c> if the member is a property; otherwise is a field.
            /// </summary>
            public bool IsProperty { get; set; }

            /// <summary>
            /// Gets the <see cref="MemberInfo"/> of this property/field.
            /// If <see cref="IsProperty"/> is true, <see cref="MemberInfo"/> is 
            /// an instance of <see cref="PropertyInfo"/>; 
            /// otherwise an instance of <see cref="FieldInfo"/>.
            /// </summary>
            public MemberInfo MemberInfo { get; set; }

            /// <summary>
            /// Gets or sets the method for getting the value of the property or field.
            /// <c>null</c> if the getter is not available.
            /// </summary>
            public Func<object, object> ValueGetter { get; set; }

            /// <summary>
            /// Gets or sets the method for setting the value of the property or field.
            /// <c>null</c> if the setter is not available.
            /// </summary>
            public Action<object, object> ValueSetter { get; set; }
        }
    }
}
